﻿using HelixToolkit.Wpf;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Media.Media3D;

namespace TestHelixToolkit
{
    public class BezierCurve3D : ParametricSurface3D, INotifyPropertyChanged
    {
        private string _uAndV;
        public string UandV
        {
            get { return _uAndV; }
            set
            {
                if (_uAndV != value)
                {
                    _uAndV = value;
                    OnPropertyChanged("UandV");
                }
            }
        }

        public float[,,] controlPoint = new float[4, 4, 3]
        {
            {
                { -6,-6,0}, {-6,-2, 10}, {-6,2,18 }, {-6,6,0 }
            },
            {
                { -2,-6,19}, {-2,-2,20 }, {-2, 2,5}, {-2,6,20 }
            },
            {
                { 2,-6,6}, {2,-2,15 }, {2,2,50 }, {2,6,10 }
            },
            {
                {6,-6,0 }, {6,-2,10 }, {6,2,10 }, { 6,6,0}
            }
        };

        private Matrix xishu = new Matrix(new double[4, 4]
        {
            { 1, 0, 0, 0 },
            { -3, 3, 0, 0 },
            { 3, -6, 3, 0 },
            { -1, 3, -3, 1 }
        });

        const double pi = Math.PI;
        public double cos(double x) { return Math.Cos(x); }
        public double sin(double x) { return Math.Sin(x); }
        public double abs(double x) { return Math.Abs(x); }
        public double sqrt(double x) { return Math.Sqrt(x); }
        public double sign(double x) { return Math.Sign(x); }
        public double sqr(double x) { return x * x; }
        public double log(double x) { return Math.Log(x); }
        public double exp(double x) { return Math.Exp(x); }
        public double pow(double x, double y) { return Math.Pow(x, y); }

        StringBuilder sb = new StringBuilder(100000);
        protected override Point3D Evaluate(double u, double v, out Point texCoord)
        {
            var p = new Point3D();
            texCoord = new Point(u, v);

            sb.Append("(" + u.ToString() + "," + v.ToString() + ")\r\n");
            if (u == 1 && v == 1)
            {
                UandV = sb.ToString();
            }
            Matrix U = new Matrix(new double[1, 4] { { 1, u, u * u, u * u * u } });
            Matrix V = new Matrix(new double[4, 1] { { 1 }, { v }, { v * v }, { v * v * v } });

            double[,] xArray = new double[4, 4];
            for (int i = 0; i < 4; i++)
            {
                for (int j = 0; j < 4; j++)
                {
                    xArray[i, j] = controlPoint[i, j, 0];
                }
            }
            double[,] yArray = new double[4, 4];
            for (int i = 0; i < 4; i++)
            {
                for (int j = 0; j < 4; j++)
                {
                    yArray[i, j] = controlPoint[i, j, 1];
                }
            }
            double[,] zArray = new double[4, 4];
            for (int i = 0; i < 4; i++)
            {
                for (int j = 0; j < 4; j++)
                {
                    zArray[i, j] = controlPoint[i, j, 2];
                }
            }

            Matrix X = new Matrix(xArray);
            Matrix Y = new Matrix(yArray);
            Matrix Z = new Matrix(zArray);

            //double a1 = pow((1 - t), 3);
            //double a2 = pow((1 - t), 2) * 3 * t;
            //double a3 = 3 * t * t * (1 - t);
            //double a4 = t * t * t;
            //ps1[j][i][0] = a1 * ps[j][0][0] + a2 * ps[j][1][0] + a3 * ps[j][2][0] + a4 * ps[j][3][0];
            //ps1[j][i][1] = a1 * ps[j][0][1] + a2 * ps[j][1][1] + a3 * ps[j][2][1] + a4 * ps[j][3][1];
            //ps1[j][i][2] = a1 * ps[j][0][2] + a2 * ps[j][1][2] + a3 * ps[j][2][2] + a4 * ps[j][3][2];
            //u *= pi;
            //v = (v - 0.5) * 2 * pi;
            //v *= 2 * pi;
            Matrix pX = U * xishu * X * xishu.Transpose() * V;
            Matrix pY = U * xishu * Y * xishu.Transpose() * V;
            Matrix pZ = U * xishu * Z * xishu.Transpose() * V;
            p.X = pX[0, 0];
            p.Y = pY[0, 0];
            p.Z = pZ[0, 0];
            return new Point3D(p.X, p.Y, p.Z);
        }

        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;

        private void OnPropertyChanged(string name)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(name));
        }

        #endregion
    }
}
